package org.dandsoft.blackbox.laboratory.tests.replace;

import org.dandsoft.blackbox.SignalId;
import org.dandsoft.blackbox.Time;

import java.util.*;

/**
 * @author Vilyuzhanin Denis (Fin)
 */
public class Replacer {

    private Map<SignalId, Trigger> replace = new Hashtable<SignalId, Trigger>();
    private Set<Trigger> triggers = new HashSet<Trigger>();
    private int maxTriggersCount;
    private int triggersCount;
    private int imageLength;
    private int sequence;
    private int level;

    public Set<SignalId> replace(Time time, Set<SignalId> signals) {
        HashSet<SignalId> result = new HashSet<SignalId>();
        for (SignalId signal : signals) {
            result.add(signal);
            if (replace.containsKey(signal)) {
                Trigger trigger = replace.get(signal);
                trigger.check(time, signal);
                if (trigger.isFound(time)) {
                    for (SignalId s : trigger.getImage()) {
                        result.remove(s);
                    }
                    trigger.incrementUseful();
                    result.add(trigger.getSignalId());
                }
            }
        }
        if (createImages(signals)) {
            return replace(time, signals);
        }
        return result;
    }

    private boolean createImages(Set<SignalId> signals) {
        boolean isNewTriggers = false;
        if (triggers.size() < maxTriggersCount) {
            Iterator<SignalId> iterator = signals.iterator();
            int counter = 0;
            int signalsCount = signals.size();
            while (iterator.hasNext()) {
                if (signalsCount - counter >= imageLength) {
                    Trigger trigger = new Trigger();
                    trigger.setSignalId(new LevelSignalId(level, sequence));
                    sequence++;
                    triggersCount++;
                    for (int i = 0; i < imageLength; i++) {
                        SignalId signal = iterator.next();
                        counter++;

                        if (!replace.containsKey(signal)) {
                            trigger.getImage().add(signal);
                        }
                    }
                    if (trigger.getImage().size() > 1) {
                        for (SignalId signal : trigger.getImage()) {
                            replace.put(signal, trigger);
                        }
                        triggers.add(trigger);
                        isNewTriggers = true;
                    }
                } else {
                    break;
                }
            }
        }
        return isNewTriggers;
    }

    public void printInfo() {
        for (Trigger trigger : triggers) {
            System.out.println("[" + trigger.getSignalId() + "](" + trigger.getUseful() + ") = " + trigger.getImage());
        }
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public int getSequence() {
        return sequence;
    }

    public void setSequence(int sequence) {
        this.sequence = sequence;
    }

    public int getMaxTriggersCount() {
        return maxTriggersCount;
    }

    public void setMaxTriggersCount(int maxTriggersCount) {
        this.maxTriggersCount = maxTriggersCount;
    }

    public int getImageLength() {
        return imageLength;
    }

    public void setImageLength(int imageLength) {
        this.imageLength = imageLength;
    }
}
